home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / gfx / misc / gnuplot-src.lha / gnuplot-3.7.1src / gnuplot-3.7.1.lha / gnuplot-3.7.1 / scanner.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-11-04  |  11.2 KB  |  377 lines

  1. #ifndef lint = open(ßÒßÒSid = "$Id: scanner.c,v 1.10 1998/11/04 14:49:57 lhecking Exp $";
  2. #endif
  3.  
  4. /* GNUPLOT - scanner.c */
  5.  
  6. /*[
  7.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted,
  11.  * provided that the above copyright notice appear in all copies and
  12.  * that both that copyright notice and this permission notice appear
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the complete modified source code.  Modifications are to
  17.  * be distributed as patches to the released version.  Permission to
  18.  * distribute binaries produced by compiling modified sources is granted,
  19.  * provided you
  20.  *   1. distribute the corresponding source modifications from the
  21.  *    released version in the form of a patch file along with the binaries,
  22.  *   2. add special version identification to distinguish your version
  23.  *    in addition to the base release version number,
  24.  *   3. provide your name and address as the primary contact for the
  25.  *    support of your modified version, and
  26.  *   4. retain our contact information in regard to use of the base
  27.  *    software.
  28.  * Permission to distribute the released version of the source code along
  29.  * with corresponding source modifications in the form of a patch file is
  30.  * granted with same provisions 2 through 4 for binary distributions.
  31.  *
  32.  * This software is provided "as is" without express or implied warranty
  33.  * to the extent permitted by applicable law.
  34. ]*/
  35.  
  36. #include "plot.h"
  37.  
  38. static int get_num __PROTO((char str[]));
  39. static void substitute __PROTO((char *str, int max));
  40.  
  41. #ifdef AMIGA_AC_5
  42. #define O_RDONLY    0
  43. int open(const char *_name, int _mode,...);
  44. int close(int);
  45. #endif /* AMIGA_AC_5 */
  46.  
  47. #ifdef VMS
  48. #include <descrip.h>
  49. #define MAILBOX "PLOT$MAILBOX"
  50. #define pclose(f) fclose(f)
  51. #ifdef __DECC
  52. #include <lib$routines.h>    /* avoid some IMPLICITFNC warnings */
  53. #include <starlet.h>
  54. #endif /* __DECC */
  55. #endif /* VMS */
  56.  
  57.  
  58. #define isident(c) (isalnum(c) || (c) == '_')
  59.  
  60. #ifndef STDOUT
  61. #define STDOUT 1
  62. #endif
  63.  
  64. #define LBRACE '{'
  65. #define RBRACE '}'
  66.  
  67. #define APPEND_TOKEN {token[t_num].length++; current++;}
  68.  
  69. #define SCAN_IDENTIFIER while (isident((int)expression[current + 1]))\
  70.                 APPEND_TOKEN
  71.  
  72. static int t_num;        /* number of token I'm working on */
  73.  
  74. /*
  75.  * scanner() breaks expression[] into lexical units, storing them in token[].
  76.  *   The total number of tokens found is returned as the function value.
  77.  *   Scanning will stop when '\0' is found in expression[], or when token[]
  78.  *     is full.
  79.  *
  80.  *       Scanning is performed by following rules:
  81.  *
  82.  *      Current char    token should contain
  83.  *     -------------    -----------------------
  84.  *      1.  alpha,_     all following alpha-numerics
  85.  *      2.  digit       0 or more following digits, 0 or 1 decimal point,
  86.  *                              0 or more digits, 0 or 1 'e' or 'E',
  87.  *                              0 or more digits.
  88.  *      3.  ^,+,-,/     only current char
  89.  *          %,~,(,)
  90.  *          [,],;,:,
  91.  *          ?,comma
  92.  *          $           for using patch (div)
  93.  *      4.  &,|,=,*     current char; also next if next is same
  94.  *      5.  !,<,>       current char; also next if next is =
  95.  *      6.  ", '        all chars up until matching quote
  96.  *      7.  #           this token cuts off scanning of the line (DFK).
  97.  *
  98.  *                      white space between tokens is ignored
  99.  */
  100. int scanner(expression)
  101. char expression[];
  102. {
  103.     register int current;    /* index of current char in expression[] */
  104.     register int quote;
  105.     char brace;
  106.  
  107.     for (current = t_num = 0; expression[current] != NUL; current++) {
  108.       again:
  109.     if (t_num + 1 >= token_table_size) {
  110.         /* leave space for dummy end token */
  111.         extend_token_table();
  112.     }
  113.     if (isspace((int) expression[current]))
  114.         continue;        /* skip the whitespace */
  115.     token[t_num].start_index = current;
  116.     token[t_num].length = 1;
  117.     token[t_num].is_token = TRUE;    /* to start with... */
  118.  
  119.     if (expression[current] == '`') {
  120.         substitute(&expression[current], MAX_LINE_LEN - current);
  121.         goto again;
  122.     }
  123.     /* allow _ to be the first character of an identifier */
  124.     if (isalpha((int) expression[current]) || expression[current] == '_') {
  125.         SCAN_IDENTIFIER;
  126.     } else if (isdigit((int) expression[current]) || expression[current] == '.') {
  127.         token[t_num].is_token = FALSE;
  128.         token[t_num].length = get_num(&expression[current]);
  129.         current += (token[t_num].length - 1);
  130.     } else if (expression[current] == LBRACE) {
  131.         token[t_num].is_token = FALSE;
  132.         token[t_num].l_val.type = CMPLX;
  133. #ifdef __PUREC__
  134.         {
  135.         char l[80];
  136.         if ((sscanf(&expression[++current], "%lf,%lf%[ }]s",
  137.                 &token[t_num].l_val.v.cmplx_val.real,
  138.                 &token[t_num].l_val.v.cmplx_val.imag,
  139.                 &l) != 3) || (!strchr(l, RBRACE)))
  140.             int_error("invalid complex constant", t_num);
  141.         }
  142. #else
  143.         if ((sscanf(&expression[++current], "%lf , %lf %c",
  144.             &token[t_num].l_val.v.cmplx_val.real,
  145.             &token[t_num].l_val.v.cmplx_val.imag,
  146.             &brace) != 3) || (brace != RBRACE))
  147.         int_error("invalid complex constant", t_num);
  148. #endif
  149.         token[t_num].length += 2;
  150.         while (expression[++current] != RBRACE) {
  151.         token[t_num].length++;
  152.         if (expression[current] == NUL)    /* { for vi % */
  153.             int_error("no matching '}'", t_num);
  154.         }
  155.     } else if (expression[current] == '\'' || expression[current] == '\"') {
  156.         token[t_num].length++;
  157.         quote = expression[current];
  158.         while (expression[++current] != quote) {
  159.         if (!expression[current]) {
  160.             expression[current] = quote;
  161.             expression[current + 1] = NUL;
  162.             break;
  163.         } else if (expression[current] == '\\'
  164.                && expression[current + 1]) {
  165.             current++;
  166.             token[t_num].length += 2;
  167.         } else
  168.             token[t_num].length++;
  169.         }
  170.     } else
  171.         switch (expression[current]) {
  172.         case '#':        /* DFK: add comments to gnuplot */
  173.         goto endline;    /* ignore the rest of the line */
  174.         case '^':
  175.         case '+':
  176.         case '-':
  177.         case '/':
  178.         case '%':
  179.         case '~':
  180.         case '(':
  181.         case ')':
  182.         case '[':
  183.         case ']':
  184.         case ';':
  185.         case ':':
  186.         case '?':
  187.         case ',':
  188.         case '$':        /* div */
  189.         break;
  190.         case '&':
  191.         case '|':
  192.         case '=':
  193.         case '*':
  194.         if (expression[current] == expression[current + 1])
  195.             APPEND_TOKEN;
  196.         break;
  197.         case '!':
  198.         case '<':
  199.         case '>':
  200.         if (expression[current + 1] == '=')
  201.             APPEND_TOKEN;
  202.         break;
  203.         default:
  204.         int_error("invalid character", t_num);
  205.         }
  206.     ++t_num;        /* next token if not white space */
  207.     }
  208.  
  209.   endline:            /* comments jump here to ignore line */
  210.  
  211. /* Now kludge an extra token which points to '\0' at end of expression[].
  212.    This is useful so printerror() looks nice even if we've fallen off the
  213.    line. */
  214.  
  215.     token[t_num].start_index = current;
  216.     token[t_num].length = 0;
  217.     /* print 3+4  then print 3+  is accepted without
  218.      * this, since string is ignored if it is not
  219.      * a token
  220.      */
  221.     token[t_num].is_token = TRUE;
  222.     return (t_num);
  223. }
  224.  
  225.  
  226. static int get_num(str)
  227. char str[];
  228. {
  229.     register int count = 0;
  230.     register long lval;
  231.  
  232.     token[t_num].is_token = FALSE;
  233.     token[t_num].l_val.type = INTGR;    /* assume unless . or E found */
  234.     while (isdigit((int) str[count]))
  235.     count++;
  236.     if (str[count] == '.') {
  237.     token[t_num].l_val.type = CMPLX;
  238.     /* swallow up digits until non-digit */
  239.     while (isdigit((int) str[++count]))
  240.         ;
  241.     /* now str[count] is other than a digit */
  242.     }
  243.     if (str[count] == 'e' || str[count] == 'E') {
  244.     token[t_num].l_val.type = CMPLX;
  245. /* modified if statement to allow + sign in exponent
  246.    rjl 26 July 1988 */
  247.     count++;
  248.     if (str[count] == '-' || str[count] == '+')
  249.         count++;
  250.     if (!isdigit((int) str[count])) {
  251.         token[t_num].start_index += count;
  252.         int_error("expecting exponent", t_num);
  253.     }
  254.     while (isdigit((int) str[++count]));
  255.     }
  256.     if (token[t_num].l_val.type == INTGR) {
  257.     lval = atol(str);
  258.     if ((token[t_num].l_val.v.int_val = lval) != lval)
  259.         int_error("integer overflow; change to floating point", t_num);
  260.     } else {
  261.     token[t_num].l_val.v.cmplx_val.imag = 0.0;
  262.     token[t_num].l_val.v.cmplx_val.real = atof(str);
  263.     }
  264.     return (count);
  265. }
  266.  
  267. #if defined(VMS) || defined(PIPES) || (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
  268.  
  269. /* this really ought to make use of the dynamic-growth of the
  270.  * input line in 3.6.  And it definitely should not have
  271.  * static arrays !
  272.  */
  273. /* A macro to reduce clutter ... */
  274. # ifdef AMIGA_AC_5
  275. #  define CLOSE_FILE_OR_PIPE ((void) close(fd))
  276. # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
  277. #  define CLOSE_FILE_OR_PIPE ((void) fclose(f); (void) unlink(atari_tmpfile))
  278. # else /* Rest of the world */
  279. #  define CLOSE_FILE_OR_PIPE ((void) pclose(f))
  280. # endif
  281.  
  282. static void substitute(str, max)    /* substitute output from ` ` */
  283. char *str;
  284. int max;
  285. {
  286.     register char *last;
  287.     register int i, c;
  288.     register FILE *f;
  289. # ifdef AMIGA_AC_5
  290.     int fd;
  291. # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
  292.     char *atari_tmpfile;
  293.     char *atari_pgm[MAX_LINE_LEN+100];
  294. # endif /* !AMIGA_AC_5 */
  295.     static char pgm[MAX_LINE_LEN+1], output[MAX_LINE_LEN+1];
  296.  
  297. # ifdef VMS
  298.     int chan, one = 1;
  299.     static $DESCRIPTOR(pgmdsc, pgm);
  300.     static $DESCRIPTOR(lognamedsc, MAILBOX);
  301. # endif /* VMS */
  302.  
  303.     /* forgive missing closing backquote at end of line */
  304.     i = 0;
  305.     last = str;
  306.     while (*++last) {
  307.     if (*last == '`') {
  308.         ++last;        /* move past it */
  309.         break;
  310.     }
  311.     pgm[i++] = *last;
  312.     }
  313.     pgm[i] = NUL;        /* end with null */
  314.     max -= strlen(last);    /* max is now the max length of output sub. */
  315.  
  316. # ifdef VMS
  317.     pgmdsc.dsc$w_length = i;
  318.     if (!((vaxc$errno = sys$crembx(0, &chan, 0, 0, 0, 0, &lognamedsc)) & 1))
  319.     os_error("sys$crembx failed", NO_CARET);
  320.  
  321.     if (!((vaxc$errno = lib$spawn(&pgmdsc, 0, &lognamedsc, &one)) & 1))
  322.     os_error("lib$spawn failed", NO_CARET);
  323.  
  324.     if ((f = fopen(MAILBOX, "r")) == NULL)
  325.     os_error("mailbox open failed", NO_CARET);
  326. # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
  327.     if (system(NULL) == 0)
  328.     os_error("no command shell", NO_CARET);
  329.     if ((strlen(atari_tmpfile) + strlen(pgm) + 5) > MAX_LINE_LEN + 100)
  330.     os_error("sorry, command to long", NO_CARET);
  331.     atari_tmpfile = tmpnam(NULL);
  332.     strcpy(atari_pgm, pgm);
  333.     strcat(atari_pgm, " >> ");
  334.     strcat(atari_pgm, atari_tmpfile);
  335.     system(atari_pgm);
  336.     if ((f = fopen(atari_tmpfile, "r")) == NULL)
  337. # elif defined(AMIGA_AC_5)
  338.     if ((fd = open(pgm, "O_RDONLY")) == -1)
  339. # else /* everyone else */
  340.     if ((f = popen(pgm, "r")) == NULL)
  341.     os_error("popen failed", NO_CARET);
  342. # endif /* !VMS */
  343.  
  344.     i = 0;
  345.     while ((c = getc(f)) != EOF) {
  346.     output[i++] = ((c == '\n') ? ' ' : c);    /* newlines become blanks */
  347.     if (i == max) {
  348.         CLOSE_FILE_OR_PIPE;
  349.         int_error("substitution overflow", t_num);
  350.     }
  351.     }
  352.  
  353.     CLOSE_FILE_OR_PIPE;
  354.  
  355.     if (i + strlen(last) > max)
  356.     int_error("substitution overflowed rest of line", t_num);
  357.     /* tack on rest of line to output */
  358.     safe_strncpy(output + i, last, MAX_LINE_LEN - i);
  359.     /* now replace ` ` with output */
  360.     safe_strncpy(str, output, max);
  361.     screen_ok = FALSE;
  362. }
  363.  
  364. #else /* VMS || PIPES || ATARI && PUREC */
  365.  
  366. static void substitute(str, max)
  367. char *str;
  368. int max;
  369. {
  370.     char line[100];
  371.  
  372.     sprintf(line, "substitution not supported by %s", OS);
  373.     int_error(line, t_num);
  374. }
  375.  
  376. #endif /* unix || VMS || PIPES || ATARI && PUREC */
  377.